﻿using Modbus.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using thinger.DataConvertLib;

namespace 七天入手上位机第一个项目
{
    /// <summary>
    /// 基于NModbus封装的ModbusTCP类
    /// </summary>
    public class NModbusTcp
    {
        //定义一个TCP客户端
        private TcpClient client;
        //定义一个Modbus主站
        private ModbusIpMaster master;
        //是否连接
        public bool IsConnnect { get; set; } = false;

        /// <summary>
        /// 连接设备
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <param name="port">端口号</param>
        /// <returns></returns>
        public int Connect(string ip, int port)
        {
            //初始化一下
            client = null;
            master = null;
            try
            {
                //实例化一个客户端
                client = new TcpClient();
                //设置soket操作
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 30);
                //发送数据超时时间
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 30);
                //连接
                client.Connect(IPAddress.Parse(ip), port);
                //实例化modbustcp主站
                master = ModbusIpMaster.CreateIp(client);
                //重试次数
                master.Transport.Retries = 3;
                //读取数据超时时间
                master.Transport.ReadTimeout = 1000;
                //连接标志置true
                IsConnnect = true;
                //连接成功
                return 1;
            }
            catch
            {
                if (client != null)
                {
                    //释放资源
                    client.Close();
                    client = null;
                }
                if (master != null)
                {
                    //释放资源
                    master.Dispose();
                    master = null;
                }
                //连接标志置false
                IsConnnect = false;
            }
            //连接失败
            return 2;

        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (client != null)
            {
                //释放资源
                client.Close();
                client = null;
            }
            if (master != null)
            {
                //释放资源
                master.Dispose();
                master = null;
            }
            //连接标志置false
            IsConnnect = false;
        }


        /// <summary>
        /// 读取输入输出线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public bool[] ReadCoils(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            bool[] rCoil = null;
            if (client.Connected == true)
            {
                //读取线圈
                rCoil = master.ReadCoils(slaveID, startAddress, length);
            }
            return rCoil;
        }

        /// <summary>
        /// 读取输入线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public bool[] ReadInputs(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            bool[] rInputs = null;
            rInputs = master.ReadInputs(slaveID, startAddress, length);
            return rInputs;
        }

        /// <summary>
        /// 读取保持型寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public ushort[] ReadHoldingRegister(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            if (master == null) return null;
            ushort[] rhreg = null;
            rhreg = master.ReadHoldingRegisters(slaveID, startAddress, length);
            return rhreg;
        }

        /// <summary>
        /// 读取float
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="length"></param>
        /// <param name="slaveID"></param>
        /// <returns></returns>
        public float ReadFloat(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            //大端模式是指数据的低位保存在内存的高位地址中，数据的高位保存在内存的低位地址中。
            //小端模式是指数据的低位保存在内存的低位地址中，数据的高位保存在内存的高位地址中。
            //ABCD = 0, // 大端形式
            //BADC = 1, // 大端单字反转
            //CDAB = 2, // 小端单字反转
            //DCBA = 3, // 小端形式
            var data = ReadHoldingRegister(startAddress, length, slaveID);
            //float[] floats = new float[data2.Length / 2];
            //floats = FloatLib.GetFloatArrayFromByteArray(ByteArrayLib.GetByteArrayFromUShortArray(data2), DataFormat.CDAB);
            float[] floats = new float[data.Length];

            byte[] bytes = ByteArrayLib.GetByteArrayFromUShortArray(data, DataFormat.ABCD);
            floats = FloatLib.GetFloatArrayFromByteArray(bytes);

            return floats[0];
        }
        /// <summary>
        /// 读取short
        /// </summary>
        /// <param name="startAddress"> 起始地址</param>
        /// <param name="length"> 读取长度</param>
        /// <param name="slaveID"> 从站地址 </param>
        /// <returns></returns>
        public short ReadShort(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            //大端模式是指数据的低位保存在内存的高位地址中，数据的高位保存在内存的低位地址中。
            var data = ReadHoldingRegister(startAddress, length, slaveID);
            //定义一个short数组
            short[] shorts = new short[data.Length];
            //将ushort数组转换为byte数组
            for (int i = 0; i < data.Length; i++)
            {
                //将ushort转换为byte数组
                byte[] bytes = ByteArrayLib.GetByteArrayFromUShort(data[i], DataFormat.ABCD);
                //将byte数组转换为short
                shorts[i] = ShortLib.GetShortFromByteArray(bytes);
            }

            return shorts[1];
        }
        /*
         public string ReadCommon(Variable variable): 这是一个公共方法，接受类型为Variable的参数，并且返回一个字符串。

switch (variable.VariableType): 这里使用了switch语句，根据Variable对象的VariableType属性的值进行分支选择。

case "bool": ... case "short": ... case "float":: 针对不同的VariableType类型，分别执行不同的操作。

if (ReadCoils(variable.VariableAddress) != null) { ... }: 在每个case分支中，首先进行了一个判断，确保可以成功读取数据。

bool[] bools = ReadCoils(variable.VariableAddress): 如果可以读取数据，就调用相应的读取方法（ReadCoils、ReadShort、ReadFloat）来获取数据。

return bools[0].ToString(), return s.ToString(), return f.ToString(): 根据不同的类型，将获取到的数据转换为字符串并返回。

catch (Exception) { ... }: 有一个异常捕获，但是异常被处理为空。
         
         */
        public string ReadCommon(Variable variable)
        {
            try
            {
                switch (variable.VariableType)
                {
                    case "bool":
                        if (ReadCoils(variable.VariableAddress) != null)
                        {
                            bool[] bools = ReadCoils(variable.VariableAddress);
                            return bools[0].ToString();
                        }
                        return null;
                    case "short":
                        if (ReadShort(variable.VariableAddress) != null)
                        {
                            short s = ReadShort(variable.VariableAddress);
                            return s.ToString();
                        }

                        return null;
                    case "float":
                        if (ReadFloat(variable.VariableAddress) != null)
                        {
                            float f = ReadFloat(variable.VariableAddress);
                            return f.ToString();
                        }
                        return null;
                }
            }
            catch (Exception)
            {


            }




            return null;
        }


        /// <summary>
        /// 读取输入寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public ushort[] ReadInputRegister(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            ushort[] rireg = null;
            rireg = master.ReadInputRegisters(slaveID, startAddress, length);
            return rireg;
        }

        /// <summary>
        /// 写入单个线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="coilAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteSingleCoil(ushort coilAddress, bool value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteSingleCoil(slaveID, coilAddress, value);
        }
        /// <summary>
        /// 写入单个寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="registerAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteSingleRegister(ushort registerAddress, ushort value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteSingleRegister(slaveID, registerAddress, value);
        }

        /// <summary>
        /// 写入多个线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteMultipleCoils(slaveID, startAddress, value);

        }
        /// <summary>
        /// 写入多个寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteMultipleRegisters(slaveID, startAddress, value);

        }
    }
}
